home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 039a / cmdlnc.zip / CMDLN.CPP next >
C/C++ Source or Header  |  1991-04-03  |  9KB  |  306 lines

  1. /*
  2.  
  3.     cmdln.cpp
  4.     3-8-91
  5.     Command line option parser
  6.  
  7.     Copyright 1991
  8.     John W. Small
  9.     All rights reserved
  10.     Use freely but acknowledge authorship and copyright.
  11.     CIS: 73757,2233
  12.  
  13.     PSW / Power SoftWare
  14.     P.O. Box 10072
  15.     McLean, Virginia 22102 8072
  16.     (703) 759-3838
  17.  
  18.  
  19.  
  20.     Notes:
  21.  
  22.  
  23.     1.  Call getOption() repeatedly to parse command
  24.     line arguments.  The options to look for along with
  25.     the argc and argv must be passed as parameters to
  26.     the constructor CmdLn() or the member function
  27.     CmdLnReset().  The options string is a string of
  28.     the option characters that may appear on your
  29.     programs command line after the switch character,
  30.     '/' or '-' for DOS.  If an option takes argument
  31.     then a colon must immediately follow that option
  32.     character in the options string to let
  33.     getOption() know to look for the argument.  The
  34.     syntax for the option string is as follows:
  35.  
  36.         options string ::= {optch[:]}*
  37.  
  38.     Your read the syntax as: An options string is zero
  39.     or more (the "*" indicates this) option characters
  40.     any of which may be followed by a colon to indicate
  41.     that the option has an argument.
  42.  
  43.  
  44.     2. GetOption() returns the current option
  45.     character being processed along with any argument
  46.     in the variable optArg.  OptArg is valid only
  47.     when an option requiring an argument is processed.
  48.     If the argument is missing then optArg == 0.  If
  49.     the current option character being processed is
  50.     unrecognized, i.e. not in the options string passed
  51.     to CmdLn(), then getOption() returns '?' with
  52.     the unrecognized character stored in optNot.  This
  53.     is the only time that optNot is valid!
  54.     getOption() returns -1 when there are no more
  55.     options to process.  The variable, optCh,
  56.     maintains a copy of the latest value returned by
  57.     getOption().
  58.  
  59.  
  60.     3.  When your program is invoked, getOption()
  61.     recognizes clusters of command line options.  A
  62.     cluster is the switch character followed immediately
  63.     by any number of option characters, no white space.
  64.     The options clusters must preceed any other command
  65.     line parameters since getOption() stops processing
  66.     on the first parameter that is not a switch.  This
  67.     is the Unix convention.  If you would like to be
  68.     able to intersperse command line switches with other
  69.     parameters on the command line then call
  70.     lookForMoreOptions() to reenable getOption()
  71.     to continue looking for more options.  If an option
  72.     takes an argument then the option's character must
  73.     be the last option in the cluster with the argument
  74.     immediately following or separated by white space.
  75.     The argument must not have any white space, though
  76.     it may contain the switch character.
  77.  
  78.     command line option cluster ::=
  79.  
  80.     {'/'|'-'}{[optch]*argch[whitespace]argument}|optch+
  81.  
  82.     Wow! That reads: a command line option cluster
  83.     starts with the switch character ('/' or '-' in DOS)
  84.     with one or more option characters (+ means one or
  85.     more) or (| means or) any number of option
  86.     characters, only the last of which is allowed to
  87.     take an argument.  The argument can be either tacked
  88.     on to the end of the option cluster or stand off by
  89.     itself.  In either case, argument contains no white
  90.     space!  If a switch character appears in a cluster
  91.     by itself or if two switch characters lead off a
  92.     cluster then no more options are processed and the
  93.     next parameter starts the non switched arguments.
  94.     This allows the first non switched argument to start
  95.     with the switch character, i.e. let the preceeding
  96.     cluster be either a single switch character or lead
  97.     off with two switch characters.  The switch
  98.     characters are defined in the static variable:
  99.     switches.  Switches is currently defined for MS DOS.
  100.  
  101.  
  102.     4.  For example, if the options string contains
  103.     "C:af:z" then 'C' and 'f' take arguments.  A valid
  104.     command line would be:
  105.  
  106.         cmd /afnew /zC cmdfile outfile
  107.  
  108.     with repeated calls to getOption() returning:
  109.  
  110.         'a'
  111.         'f' with optArg == "new"
  112.         'z'
  113.         'C' with optArg == "cmdfile"
  114.         -1  with Argi() == 4
  115.  
  116.     The variable, argi, is the index into the next
  117.     unprocessed argv cell.  You can use Argi() to
  118.     initialize your index into the non-switched
  119.     command line parameters.
  120.  
  121.  
  122.     5.  Compile and run cmdln.cpp by defining
  123.     TEST_CMDLN_CPP towards the end of this file.
  124.     By defining TEST_CMDLN_CPP you can compile the
  125.     demo/test version of cmdln.cpp.  Be sure you
  126.     understand the demo/test code before using
  127.     cmdln.cpp.
  128.  
  129. */
  130.  
  131. #include <string.h>    /*  strchr()  */
  132. #include <cmdln.hpp>
  133.  
  134. static char switches[] = "/-";
  135. /*
  136.     Switches is initialized here for DOS switch
  137.     characters.  Change as necessary for your
  138.     host OS shell.
  139. */
  140.  
  141. void CmdLn::CmdLnReset(int argc, char *argv[],
  142.     char *options)
  143. {
  144.     this->argv = argv;
  145.     this->options = options;
  146.     opt = (char *) 0;
  147.     this->argc = argc;
  148.     optEnd = 0;
  149.     optCh = optNot = '\0';
  150.     optArg = (char *) 0;
  151.     argi = 1;
  152. }
  153.  
  154. int CmdLn::getOption(void)
  155. {
  156.  
  157.     char *lookup;
  158.  
  159.     optArg = (char *)0;
  160.     if (optEnd)    /* no more options allowed */
  161.         return (optCh = 0);
  162.     if (!opt || (*opt == '\0'))  {
  163.         if (argi >= argc) /* no more parameters */
  164.             return (optEnd = optCh = -1);
  165.             /* end of options */
  166.         opt = argv[argi];
  167.             /* next possible option cluster */
  168.         if (!strchr(switches,*opt))
  169.             /* Not an option cluster? */
  170.             return (optEnd = optCh = -1);
  171.             /* start non option parameters */
  172.         argi++; /* next possible parameter */
  173.         opt++;  /* next possible option */
  174.         if (!*opt || strchr(switches,*opt))
  175.             /* Two switches or one by itself */
  176.             return (optEnd = optCh = -1);
  177.             /* means end of options */
  178.     }
  179.     if ((lookup = strchr(
  180.         /* validate option character */
  181.         options? options : "",
  182.         optNot = *opt++))
  183.         == (char *)0)
  184.         return (optCh = '?');
  185.         /* unknown option */
  186.     if (lookup[1] == ':')  {
  187.         /* option takes argument */
  188.         if (*opt != '\0')
  189.             /* Is argument in this parameter? */
  190.             optArg = opt;
  191.         else if (argi < argc)
  192.             /* Is argument in next parameter? */
  193.             optArg = argv[argi++];
  194.         opt = (char *) 0;
  195.         /* no more options in this parameter */
  196.     }
  197.     return (optCh = *lookup);
  198.     /* return option */
  199. }
  200.  
  201. void CmdLn::nextCluster(void) { opt = (char *) 0; }
  202.     /* start processing in next cluster */
  203.  
  204. void CmdLn::lookForMoreOptions(void)
  205. {
  206.     if (optEnd)  {
  207.         opt = (char *) 0;
  208.         argi++;
  209.         optEnd = 0;
  210.     }
  211. }
  212.  
  213.  
  214. /*
  215.     To use cmdln.cpp in your own programs be sure to
  216.     comment out the following "#define TEST_CMDLN_CPP."
  217. */
  218. #define TEST_CMDLN_CPP
  219. #ifdef TEST_CMDLN_CPP
  220.  
  221. #include <stdio.h>
  222.  
  223. char *help[] = {
  224.     "\nusage: cmdln -ooptions *",
  225.     "\nwhere 'options' consists of the letters to "
  226.     "look for, and",
  227.     "\n      '*' are the command line arguments to"
  228.     " be parsed by 'options.'",
  229.     "\n      For the purposes of this test 'o' "
  230.     "switches are skipped.",
  231.     "\n\nFor example, with the command line: ",
  232.     "\n\n    cmdln /oC:af:z /afnew /zC cmdfile outfile",
  233.     "\n\nthe 'options' string is 'C:af:z', which "
  234.     "means that this particular invocation",
  235.     "\nof the demo will recognize 'C', 'a', 'f' "
  236.     "and 'z' as switch options.  'C' and",
  237.     "\n'f' take arguments, which is indicated by"
  238.     " the colon after each in the 'options'",
  239.     "\nstring.  Switch options are introduced by "
  240.     "'/' or '-' in DOS.  The 'options'",
  241.     "\nstring is then used to parse the rest of "
  242.     "the command line.  In this case it",
  243.     "\nrecognizes 'a', 'f' with argument 'new', "
  244.     "'z', and 'C' with argument 'cmdfile.'",
  245.     "\nRun this demo with command lines similar "
  246.     "to this example to see how it",
  247.     "\nworks.  Then besure to read the notes in "
  248.     "cmdln.cpp for complete instructions on",
  249.     "\nhow to use the CmdLn class.  The source "
  250.     "code of this demo is also found in",
  251.     "\ncmdln.cpp.  Be sure to study how I coded "
  252.     "the demo.  You will then be ready to",
  253.     "\nstart coding with the CmdLn class.\n",
  254.     0
  255. };
  256.  
  257. main(int argc, char *argv[])
  258. {
  259.     int i;
  260.     CmdLn CL(argc,argv,"o:");
  261.  
  262.     (void) CL.getOption();
  263.     if ((CL.optCh != 'o') || !CL.optArg)  {
  264.         for (i = 0; help[i]; i++)
  265.             printf("%s",help[i]);
  266.         return 1;
  267.     }
  268.     printf("\nTest the CmdLn class instance 'CL'");
  269.     printf(" with the following command line:");
  270.     printf("\n\n      ");
  271.     for (i = 0; i < argc; i++)
  272.         printf("%s ",argv[i]);
  273.     printf("\n\nParse for the following options: \n");
  274.     for (i = 0; CL.optArg[i]; i++)  {
  275.         printf("\n      %c",CL.optArg[i]);
  276.         if (CL.optArg[i+1] == ':') {
  277.                 i++;
  278.                 printf("   with argument");
  279.         }
  280.     }
  281.     printf("\n\nParameters parsed by 'CL' as ...\n");
  282.  
  283.     CL.CmdLnReset(argc, argv, CL.optArg);
  284.     do  {
  285.       while (CL.getOption() != -1)
  286.         if (CL.optCh == '?')
  287.           if (CL.optNot == 'o')
  288.         CL.nextCluster();
  289.           else
  290.         printf("\n      CL.optNot:  %c",CL.optNot);
  291.         else  {
  292.           printf("\n      CL.optCh:   %c",CL.optCh);
  293.           printf("    CL.optArg:  %s",CL.optArg);
  294.         }
  295.         if (CL.Argi() < argc)  {
  296.           printf("\n      CL.Argi():  %d",CL.Argi());
  297.           printf("    argv[%d]:    %s",
  298.         CL.Argi(),argv[CL.Argi()]);
  299.         }
  300.         CL.lookForMoreOptions();
  301.     } while (CL.Argi() < argc);
  302.     printf("\n");
  303.     return 0;
  304. }
  305.  
  306. #endif